/*
fluttershy.c -- Fluttery Watchface for Pebble

Copyright (c) 2014 Jeffry Johnston <pebble@kidsquid.com>

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
pebble new-project fluttershy
pebble build
pebble install --phone 192.168.1.108
*/

#include <pebble.h>

static Window *main_window;
static Layer *main_window_layer;
static GBitmap *pony_image;
static GBitmap *cutie_mark_image;
static GBitmap *large_digit_image[11]; /* 0-9 space */
static GBitmap *small_digit_image[11]; /* 0-9 space */
                                   /* 01234567890123 */
static GBitmap *letter_image[14]; /* ADEFHIMNORSTUW */
static const int weekday_names[7][3] = {{10, 12, 7}, {6, 8, 7}, {11, 12, 2}, {13, 2, 1}, {11, 4, 12}, {3, 9, 5}, {10, 0, 11}};

static struct tm *current_time = NULL;
static int time_digits[4];
static int date_digits[4];
static int weekday;

static bool bluetooth_connected;
static BatteryChargeState battery;

/******************************************************************************/
/* Data Collection                                                            */
/******************************************************************************/
static void set_time(struct tm *tm)
{
	time_t now;
	int hour;

	if (tm == NULL) {
		now = time(NULL);
		current_time = localtime(&now);
	} else {
		current_time = tm;
	}

	hour = (current_time->tm_hour) % 12;
	if (hour == 0) {
		hour = 12;
	}
	time_digits[0] = (hour > 9) ? 1 : 10;
	time_digits[1] = hour % 10;
	time_digits[2] = (current_time->tm_min) / 10;
	time_digits[3] = (current_time->tm_min) % 10;
}

static void set_weekday_and_date()
{
	int month = current_time->tm_mon + 1;

	weekday = current_time->tm_wday;
	date_digits[0] = (month > 9) ? 1 : 10;
	date_digits[1] = month % 10;
	date_digits[2] = (current_time->tm_mday) / 10;
	date_digits[3] = (current_time->tm_mday) % 10;
}

/******************************************************************************/
/* Handlers                                                                   */
/******************************************************************************/
static void minute_tick_handler(struct tm *tm, TimeUnits units_changed)
{
	// set time
	set_time(tm);

	// set weekday and date hourly
	if (current_time->tm_min == 0) {
		set_weekday_and_date();
	}

	layer_mark_dirty(main_window_layer);
}

static void bluetooth_connection_handler(bool connected)
{
	bluetooth_connected = connected;
	layer_mark_dirty(main_window_layer);
}

static void battery_state_handler(BatteryChargeState charge)
{
	battery = charge;
	layer_mark_dirty(main_window_layer);
}

/******************************************************************************/
/* Draw Display                                                               */
/******************************************************************************/
static void main_window_layer_update_callback(Layer *layer, GContext *ctx)
{
	int i;
	int j;
	int k;
	
	// draw pony 
	graphics_draw_bitmap_in_rect(ctx, pony_image, (GRect) { .origin = { 0, 0 }, .size = pony_image->bounds.size });
	
	// draw cutie mark
	if (bluetooth_connected) {
		graphics_draw_bitmap_in_rect(ctx, cutie_mark_image, (GRect) { .origin = { 67, 95 }, .size = cutie_mark_image->bounds.size });
	}
	
	// draw battery level
	i = battery.charge_percent / 10;
	if (i > 0) {
		graphics_context_set_fill_color(ctx, GColorBlack);
		graphics_fill_rect(ctx, (GRect) { .origin = { 54, 16 - i }, .size = { 4, i }}, 0, GCornerNone);
	}
	
	// draw weekday
	for (i = 0; i < 3; ++i) {
		k = weekday_names[weekday][i];
		graphics_draw_bitmap_in_rect(ctx, letter_image[k], (GRect) { .origin = { 12 * i + 6, 3 }, .size = letter_image[k]->bounds.size });
	}
	
	// draw time
	for (i = 0, j = 0; i < 4; ++i, j += 14) {
		if (i == 2) {
			j += 4;
		}
		k = time_digits[i];
		graphics_draw_bitmap_in_rect(ctx, large_digit_image[k], (GRect) { .origin = { j + 2, 21 }, .size = large_digit_image[k]->bounds.size });
	}

	// draw date
	for (i = 0, j = 0; i < 4; ++i, j += 10) {
		if (i == 2) {
			j += 6;
		}
		k = date_digits[i];
		graphics_draw_bitmap_in_rect(ctx, small_digit_image[k], (GRect) { .origin = { j + 4, 48 }, .size = small_digit_image[k]->bounds.size });
	}
}

/******************************************************************************/
/* Initialization and Exit                                                    */
/******************************************************************************/
static void main_window_load(Window *window)
{
	int i;
	
	// set callbacks
	main_window_layer = window_get_root_layer(window);
	layer_set_update_proc(main_window_layer, main_window_layer_update_callback);

	// load images
	pony_image = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_PONY);
	cutie_mark_image = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_CUTIE_MARK);
	for (i = 0; i < 11; ++i) {
		large_digit_image[i] = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_LARGE_0 + i);
	}
	for (i = 0; i < 11; ++i) {
		small_digit_image[i] = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_SMALL_0 + i);
	}
	for (i = 0; i < 14; ++i) {
		letter_image[i] = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_LETTER_A + i);
	}
}

static void main_window_unload(Window *window)
{
	int i;
	
	// destroy images
	gbitmap_destroy(pony_image);
	gbitmap_destroy(cutie_mark_image);
	for (i = 0; i < 11; ++i) {
		gbitmap_destroy(large_digit_image[i]);
	}
	for (i = 0; i < 11; ++i) {
		gbitmap_destroy(small_digit_image[i]);
	}
	for (i = 0; i < 14; ++i) {
		gbitmap_destroy(letter_image[i]);
	}
}

static void init(void)
{
	// create main window
	main_window = window_create();
	window_set_fullscreen(main_window, true);
	window_set_window_handlers(main_window, (WindowHandlers) {
		.load = main_window_load,
		.unload = main_window_unload,
	});
	window_stack_push(main_window, false);
	
	// get initial data values
	bluetooth_connected = bluetooth_connection_service_peek();
	set_time(NULL);
	set_weekday_and_date();
	battery = battery_state_service_peek();
	
	// set handlers
	tick_timer_service_subscribe(MINUTE_UNIT, minute_tick_handler);
	bluetooth_connection_service_subscribe(bluetooth_connection_handler);
	battery_state_service_subscribe(battery_state_handler);
}

static void deinit(void)
{
	tick_timer_service_unsubscribe();
	bluetooth_connection_service_unsubscribe();
	battery_state_service_unsubscribe();
}

int main(void)
{
	init();
	app_event_loop();
	deinit();
	return 0;
}

